home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / disk / ocop.zip / OCOP.CPP next >
C/C++ Source or Header  |  1993-01-11  |  26KB  |  635 lines

  1. /*
  2.     OCOP.CPP:  a diskette copy optimizer
  3.     -------------------------------------
  4.     Garry J. Vass
  5.     Gundhof Str 18
  6.     D6000 Frankfurt 71
  7.     Germany
  8.   
  9.     It is not easy to explain why this utility exists.  In 1986,
  10.     I was travelling all over the globe with diskettes.  Sometimes
  11.     I arrived at some place only to learn that my diskettes were
  12.     faulty - somewhat embarrassing to say the least.  So I wrote
  13.     a small assembler program called OPTCOPY.COM, that copied files
  14.     and read them back 10 times.  Reliability went up, but I was
  15.     bothered because I was carrying too many diskettes.  I wanted
  16.     reliability and optimization.
  17.  
  18.     In 1988, I wrote SAFECOPY.COM.  With this I was satisfied, and
  19.     it worked well for almost 5 years.  Some of my Sysop buddies had
  20.     been using OPTCOPY and naturally wanted the upgrade, so I passed
  21.     it around.  I even uploaded it to Compuserve and it was still 
  22.     there in 1993.  Those were the days of DOS 2.1, and being the
  23.     cautious sort, I included a hook that stopped the program from
  24.     running if it encountered anything higher than DOS 3.X (who could
  25.     imagine something beyond DOS 3?).
  26.     
  27.     To my astonishment, DOS survived into DOS 5.  To my further
  28.     astonishmment, SAFECOPY had managed to find itself a secure
  29.     niche of users who bitched and wanted a DOS 5 version.
  30.     
  31.     So here is OCOP.  It is not great software.  It is simply
  32.     a utility that somebody like NORTON or CENTRAL POINT should
  33.     have done in a flashy way.  Oh, by the way, it is called
  34.     OCOP (not OCOPY) because of the differences between German
  35.     and American keyboards.
  36.     
  37.     Times change, in these days of virus-infested media, a utility
  38.     of this sort demands source.  The source lies below. 
  39.     
  40.     If you use this program, keep the source safe because I
  41.     do not plan on issuing upgrades.  It works for me.
  42.     
  43.     Rights.  I abandon all rights and all responsibility
  44.     associated with this product.
  45.     
  46.     The source compiles under Borland 3.1 with the command
  47.     line bcc -ml ocop.cpp.
  48.     
  49. */    
  50. /***************************************************************/
  51. /*                                                             */
  52. /*                                                             */
  53. /*                                                             */
  54. /*                                                             */
  55. /***************************************************************/
  56. #include  <stdio.h>  // some basic rtl includes
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include  <ctype.h>
  60. #include  <conio.h>
  61. #include    <dir.h>
  62. #include    <dos.h>
  63. /***************************************************************/
  64. /*                                                             */
  65. /*                                                             */
  66. /*                                                             */
  67. /*                                                             */
  68. /***************************************************************/
  69. typedef struct sFI {        // your basic heap administration
  70.         struct find_t blk;  // structure
  71.         char dirof[ 128 ];
  72.         int status[ 2 ];
  73.         struct sFI *next;
  74.         }sfxxx;
  75. /***************************************************************/
  76. /*                                                             */
  77. /*                                                             */
  78. /*                                                             */
  79. /*                                                             */
  80. /***************************************************************/
  81. struct sFI *Rootdirs = NULL;   // some global variables
  82. struct sFI *Rootfiles = NULL;
  83. char Cmd[ 200 ];
  84. char Basecwd[ 128 ];
  85. char Spec[ 128 ];
  86. long Total;
  87. int Flag_subdirs = 0;
  88. int Flag_usezip  = 0;
  89. char Argv1[ 50 ];
  90. char Argv2[ 50 ];
  91. /***************************************************************/
  92. /*                                                             */
  93. /*                                                             */
  94. /*                                                             */
  95. /*                                                             */
  96. /***************************************************************/
  97. void drain( void )  // clear the keyboard buffer
  98. {
  99.     while( kbhit() ) 
  100.            getch();
  101. }
  102. /***************************************************************/
  103. /*                                                             */
  104. /*                                                             */
  105. /*                                                             */
  106. /*                                                             */
  107. /***************************************************************/
  108. void hitakey( void )  // take a bold guess what this does...
  109. {
  110.     printf( "\n\n\n ----->Hit a key..." );
  111.     getch();
  112.     drain();
  113. }
  114. /***************************************************************/
  115. /*                                                             */
  116. /*                                                             */
  117. /*                                                             */
  118. /*                                                             */
  119. /***************************************************************/
  120. int removedoubles( char *s )  // the lazy programmer's method
  121. {                             // for getting path names correct
  122.     if( !strlen( s ) ) return( 0 );
  123.     char *p = strstr( s, "\\\\" );
  124.     while( p ) {
  125.            strcpy( p, p + 1 );
  126.            removedoubles( s );
  127.            p = strstr( s, "\\\\" );
  128.     }
  129.     return( 1 );
  130. }
  131. /***************************************************************/
  132. /*                                                             */
  133. /*                                                             */
  134. /*                                                             */
  135. /*                                                             */
  136. /***************************************************************/
  137. int insertdirlist( char *s, struct find_t *b )  // stuff a directory 
  138. {          
  139.     struct sFI *n;
  140.     n = (struct sFI *)malloc( sizeof( struct sFI ) );
  141.     if( n ) {
  142.         memmove( &n -> blk, b, sizeof( struct find_t ) );
  143.         strcpy( n -> dirof, s );
  144.         memset( n -> status, 0, 4 * sizeof( int ) );
  145.         n -> next = NULL;
  146.         if( !Rootdirs ) {
  147.             Rootdirs = n;
  148.         } else {
  149.             n -> next = Rootdirs;
  150.             Rootdirs = n;
  151.         }
  152.         return( 1 );
  153.     }
  154.     return( 0 );
  155. }
  156. /***************************************************************/
  157. /*                                                             */
  158. /*                                                             */
  159. /*                                                             */
  160. /*                                                             */
  161. /***************************************************************/
  162. int insertfilelist( char *s, struct find_t *b )  // stuff a file
  163. {
  164.     struct sFI *n;
  165.     n = (struct sFI *)malloc( sizeof( struct sFI ) );
  166.     if( n ) {
  167.         memmove( &n -> blk, b, sizeof( struct find_t ) );
  168.         removedoubles( s );
  169.         strcpy( n -> dirof, s );
  170.         memset( n -> status, 0, 4 * sizeof( int ) );
  171.         n -> next = NULL;
  172.         if( !Rootfiles ) {
  173.             Rootfiles = n;
  174.         } else {
  175.             if( n -> blk.size > Rootfiles -> blk.size ) {
  176.                 n -> next = Rootfiles;
  177.                 Rootfiles = n;
  178.             } else {
  179.                 struct sFI *p = Rootfiles;
  180.                 for( struct sFI *i = Rootfiles; i; i = i -> next ) {
  181.                      if( n -> blk.size > i -> blk.size ) {
  182.                          n -> next = i;
  183.                          p -> next = n;
  184.                          return( 1 );
  185.                      }
  186.                      if( !i -> next ) {
  187.                          i -> next = n;
  188.                          return( 1 );
  189.                      }
  190.                      p = i;
  191.                 }
  192.             }
  193.         }
  194.         return( 1 );
  195.     }
  196.     return( 0 );
  197. }
  198. /***************************************************************/
  199. /*                                                             */
  200. /*                                                             */
  201. /*                                                             */
  202. /*                                                             */
  203. /***************************************************************/
  204. int walkcopied( void )  // stroll down the list of copied files
  205. {
  206. int ret = 0;
  207.     for( struct sFI *i = Rootfiles; i; i = i -> next ) {
  208.          if( i -> status[ 0 ] ) {
  209.              printf( "%s\\%s  %ld ...copied....\n", i -> dirof, i -> blk.name, i -> blk.size );
  210.              drain();
  211.          }
  212.     }
  213.     return( ret );
  214. }
  215. /***************************************************************/
  216. /*                                                             */
  217. /*                                                             */
  218. /*                                                             */
  219. /*                                                             */
  220. /***************************************************************/
  221. int walknotcopied( void )  // stroll down the list of files yet to come.
  222. {
  223. int ret = 0;
  224.     for( struct sFI *i = Rootfiles; i; i = i -> next ) {
  225.          if( !i -> status[ 0 ] ) {
  226.              printf( "%s\\%s  %ld ...not copied....\n", i -> dirof, i -> blk.name, i -> blk.size );
  227.              printf( "\ta.  next file\n" );
  228.              printf( "\tb.  forget about this file - skip it\n" );
  229.              printf( "\tc.  exit the walker\n" );
  230.              drain();
  231.              char c = toupper( getch() );
  232.              switch( c ) {
  233.                      case 'B':
  234.                           i -> status[ 0 ] = 2;
  235.                           break;
  236.                      case 'C':
  237.                           return( ret );
  238.              }
  239.          }
  240.     }
  241.     return( ret );
  242. }
  243. /***************************************************************/
  244. /*                                                             */
  245. /*                                                             */
  246. /*                                                             */
  247. /*                                                             */
  248. /***************************************************************/
  249. int walkdriver( void )  // manage the strolling process
  250. {
  251. int ret = 0;
  252.     walktop:
  253.     clrscr();
  254.     printf( "a.  Walk files that have been copied\n" );
  255.     printf( "b.  Walk files not yet copied\n" );
  256.     printf( "q.  Leave the walker\n" );
  257.     drain();
  258.     ret = toupper( getch() );
  259.     switch( ret ) {
  260.             case 'A':
  261.                  walkcopied();
  262.                  goto walktop;
  263.             case 'B':
  264.                  walknotcopied();
  265.                  goto walktop;
  266.             case 'Q':
  267.                  return( 1 );
  268.             default: 
  269.                  goto walktop;
  270.     }
  271.     return( ret );
  272. }
  273. /***************************************************************/
  274. /*                                                             */
  275. /*                                                             */
  276. /*                                                             */
  277. /*                                                             */
  278. /***************************************************************/
  279. int more( long *total )  // anything else to do?
  280. {
  281.     int ret = 0;
  282.     *total = 0L;
  283.     for( struct sFI *i = Rootfiles; i; i = i -> next ) {
  284.          if( !i -> status[ 0 ] ) {
  285.              ++ret;
  286.              *total += i -> blk.size;
  287.          }
  288.     }
  289.     return( ret );
  290. }
  291. /***************************************************************/
  292. /*                                                             */
  293. /*                                                             */
  294. /*                                                             */
  295. /*                                                             */
  296. /***************************************************************/
  297. struct sFI *select( long m )  // find a file of length less than "m"
  298. {
  299.     for( struct sFI *i = Rootfiles; i; i = i -> next ) {
  300.          if( i -> blk.size < m && i -> status[ 0 ] == 0 ) {
  301.              return( i );
  302.          }
  303.     }
  304.     return( NULL );
  305. }
  306. /***************************************************************/
  307. /*                                                             */
  308. /*                                                             */
  309. /*                                                             */
  310. /*                                                             */
  311. /***************************************************************/
  312. int builddirlist( char *p, char *s ) // build a heap of directories
  313. {
  314.     char temp[ 128 ];
  315.     struct find_t blk;
  316.     int done;
  317.     strcpy( temp, p );
  318.     sprintf( Spec, "%s\\%s", temp, s );
  319.     removedoubles( Spec );
  320.     done = _dos_findfirst( Spec , 0xFF, &blk );
  321.     while( !done ) {
  322.            if( blk.attrib == FA_DIREC) {
  323.                if( blk.name[ 0 ] != '.' ) {
  324.                    insertdirlist( p, &blk );
  325.                    sprintf( temp, "%s\\%s", p, blk.name );
  326.                    builddirlist( temp, s );
  327.                }
  328.            }
  329.            done = _dos_findnext( &blk );
  330.     }
  331.     return( 0 );
  332. }
  333. /***************************************************************/
  334. /*                                                             */
  335. /*                                                             */
  336. /*                                                             */
  337. /*                                                             */
  338. /***************************************************************/
  339. int scandir( char *pname, char *dname, char *args )  // look in the directory
  340. {
  341.     char temp[ 128 ];
  342.     struct find_t blk;
  343.     sprintf( temp, "%s\\%s\\%s", pname, dname, args );
  344.     removedoubles( temp );
  345.     int done = _dos_findfirst( temp, 0xFF, &blk );
  346.     while( !done ) {
  347.            switch( blk.attrib ) {
  348.                    case FA_RDONLY:
  349.                    case FA_HIDDEN:
  350.                    case FA_LABEL:
  351.                    case FA_SYSTEM:
  352.                    case 0x28:
  353.                    case FA_DIREC:
  354.                         break;
  355.                    case FA_ARCH:
  356.                    default:
  357.                         sprintf( temp, "%s\\%s", pname, dname );
  358.                         insertfilelist( temp, &blk );
  359.                         break;
  360.            }
  361.            done = _dos_findnext( &blk );
  362.     }
  363.     return( 1 );
  364. }
  365. /***************************************************************/
  366. /*                                                             */
  367. /*                                                             */
  368. /*                                                             */
  369. /*                                                             */
  370. /***************************************************************/
  371. int buildfilelist( char *s ) // build a list of files
  372. {
  373.     for( struct sFI *d = Rootdirs; d; d = d -> next ) {
  374.          scandir( d -> dirof, d -> blk.name, s );
  375.     }
  376.     return( 0 );
  377. }
  378. /***************************************************************/
  379. /*                                                             */
  380. /*                                                             */
  381. /*                                                             */
  382. /*                                                             */
  383. /***************************************************************/
  384. int driveexists( char *s )  // lazy programmer's way to see if a drive exists
  385. {
  386.     unsigned current;
  387.     unsigned md;
  388.     unsigned t;
  389.     unsigned target = *s - 'A' + 1;
  390.     _dos_getdrive( ¤t );
  391.     _dos_setdrive( target, &md );
  392.     _dos_getdrive( &t );
  393.     _dos_setdrive( current, &md );
  394.     if( t == target ) {
  395.         return( 1 );
  396.     }
  397.     return( 0 );
  398. }
  399. /***************************************************************/
  400. /*                                                             */
  401. /*                                                             */
  402. /*                                                             */
  403. /*                                                             */
  404. /***************************************************************/
  405. long dfs( char *s ) // just what it says <g>.  disk free space.
  406. {
  407.     struct diskfree_t free;
  408.     long avail;
  409.     clrscr();
  410.     gotoxy( 1, 1 ); printf( "Checking free space on %s", s );
  411.     int dnumber = *s - 'A' + 1;
  412.     if( _dos_getdiskfree( dnumber, &free ) != 0 ) {
  413.         return( 0 );
  414.     }
  415.     avail = (long)free.avail_clusters * (long)free.bytes_per_sector* (long) free.sectors_per_cluster;
  416.     gotoxy( 1, 1 ); printf( "%-4s reports %12ld bytes available", s, avail );
  417.     return( avail );
  418. }
  419. /***************************************************************/
  420. /*                                                             */
  421. /*                                                             */
  422. /*                                                             */
  423. /*                                                             */
  424. /***************************************************************/
  425. int parseargs( int argc, char *argv[] ) // the VERY lazy programmer's
  426. {                                       // way to parse the command tail.
  427. char allargs[ 128 ];
  428. char *p;
  429. /*
  430.     ARGV        CONTENTS
  431.     --------------------
  432.     1           source specification (*.*, etc)
  433.     2           destination drive (a:, etc)
  434.     3           optional /s (re xcopy)
  435.     4           optional /z (use pkzip where possible)
  436. */
  437.     strcpy( allargs, "" );
  438.     for( int i = 1; i < argc; i++ ) {
  439.          strupr( argv[ i ] );
  440.          strcat( allargs, argv[ i ] );
  441.     }
  442.     if( strstr( allargs, "/S" ) ) 
  443.         Flag_subdirs = 1;
  444.     if( strstr( allargs, "/Z" ) ) {
  445.         if( searchpath( "PKZIP.COM" ) || searchpath( "PKZIP.EXE" ) ) {
  446.             Flag_usezip = 1;
  447.         } else {
  448.             printf( "Cannot find PKZIP.COM or PKZIP.EXE\n" );
  449.             return( 0 );
  450.         }
  451.     }
  452.     strcpy( Argv1, argv[ 1 ] );
  453.     strcpy( Argv2, argv[ 2 ] );
  454.     if( !driveexists( Argv2 ) ) {
  455.         printf( "Unable to locate destination drive %s\n", Argv2 );
  456.         return( 0 );
  457.     }
  458.     return( 1 );
  459. }
  460. /***************************************************************/
  461. /*                                                             */
  462. /*                                                             */
  463. /*                                                             */
  464. /*                                                             */
  465. /***************************************************************/
  466. int quit( void ) // hmmmm...  I can't remember what this does...
  467. {
  468.     chdir( Basecwd );
  469.     printf( "You are now in %s\n", Basecwd );
  470.     exit( 0 );
  471.     return( 1 );
  472. }
  473. /***************************************************************/
  474. /*                                                             */
  475. /*                                                             */
  476. /*                                                             */
  477. /*                                                             */
  478. /***************************************************************/
  479. char  drive[ 25 ];
  480. char   dir[ 128 ];
  481. char   name[ 25 ];
  482. char    ext[ 25 ];
  483. char  Dest[ 128 ];
  484. int dothework( char *ddrive, struct sFI *s ) // here is where the work 
  485. {                                            // gets done...
  486.     if( Flag_usezip && !( strstr( s -> blk.name, ".ZIP" ) ) ) {
  487.         fnsplit( s -> blk.name, drive, dir, name, ext );
  488.         sprintf( Cmd, "pkzip -a %s%s.zip  %s\\%s ", ddrive, name, s -> dirof, s -> blk.name, ddrive );
  489.         sprintf( Dest, "%s%s.ZIP", ddrive, name );
  490.     } else {
  491.         sprintf( Cmd, "xcopy %s\\%s  %s", s -> dirof, s -> blk.name, ddrive );
  492.         sprintf( Dest, "%s%s", ddrive, s -> blk.name );
  493.     }
  494.     removedoubles( Cmd );
  495.     gotoxy( 1, 3 );printf( "%-79s\n", Cmd );
  496.     system( Cmd );
  497.     if( kbhit() ) {
  498.         return( 0 );
  499.     }
  500.     sprintf( Cmd, "copy %s NUL", Dest );
  501.     removedoubles( Cmd );
  502.     gotoxy( 1, 8 );printf( "%-79s\n", Cmd );
  503.     system( Cmd );
  504.     return( 1 );
  505. }
  506. /***************************************************************/
  507. /*                                                             */
  508. /*                                                             */
  509. /*                                                             */
  510. /*                                                             */
  511. /***************************************************************/
  512. int pl( void ) // select a file and copy it
  513. {
  514.     while( more( &Total ) ) {
  515.            long df = dfs( Argv2 );
  516.            if( kbhit() ) {
  517.                 break;
  518.            }
  519.            if( df == 0 ) {
  520.                break;
  521.            }
  522.            struct sFI *s = select( df );
  523.            if( s ) {
  524.                gotoxy( 1, 2 ); printf( "%-14s (%10ld) selected ", s -> blk.name, s -> blk.size );
  525.                s -> status[ 0 ] += dothework( Argv2, s );
  526.            }
  527.     }
  528.     return( 1 );
  529. }    
  530. /***************************************************************/
  531. /*                                                             */
  532. /*                                                             */
  533. /*                                                             */
  534. /*                                                             */
  535. /***************************************************************/
  536. int main( int argc, char *argv[] )
  537. {
  538. int m;
  539. int ch;
  540.     clrscr();
  541.     getcwd( Basecwd, 128 );
  542.     if( argc < 3 ) {
  543.         printf( "OCOPY:  a diskette optimizer\n" );
  544.         printf( "----------------------------\n" );
  545.         printf( "usage:  ocop  [spec] [dest] {options}\n\n" );
  546.         printf( "              spec = source file specification\n" );
  547.         printf( "              dest = destination drive\n" );
  548.         printf( "              options\n" );
  549.         printf( "                     /S = include subdirectories\n" );
  550.         printf( "                     /Z = use PKZIP where appropriate\n\n\n" );
  551.         printf( "example:  ocop *.* a: /S /Z\n" );
  552.         quit();
  553.     }
  554.     if( parseargs( argc, argv ) ) {
  555.         if( Flag_subdirs ) {
  556.             builddirlist( Basecwd, "*.*" );
  557.             buildfilelist( Argv1 );
  558.         }
  559.         scandir( Basecwd, "", Argv1 );
  560.     } else {
  561.         quit();
  562.     }
  563.     restart:
  564.     m = more( &Total );
  565.     long df = dfs( Argv2 );
  566.     if( m ) {
  567.         mtop:
  568.         clrscr();
  569.         drain();
  570.         printf( "There are yet %d files (%ld bytes) left to copy\n", m, Total );
  571.         printf( "There are %ld bytes left on %s\n", df, Argv2 );
  572.         printf( "Menu:  \n" );
  573.         printf( "a.  continue coping (i.e., %s is ready)\n", Argv2 );
  574.         printf( "d.  perform a DIR on %s \n", Argv2 );
  575.         printf( "c.  perform a chkdsk on %s\n", Argv2 );
  576.         printf( "e.  erase the files on %s\n", Argv2 );
  577.         printf( "f.  dothework the diskette in %s\n", Argv2 );
  578.         printf( "s.  shell exit to dos\n", Argv2 );
  579.         printf( "w.  walk the list of files\n" );
  580.         printf( "q.  quit this program\n" );
  581.         drain();
  582.         ch = toupper( getch() );
  583.         clrscr();
  584.         switch( ch ) {
  585.                 case 'A': 
  586.                      pl();
  587.                      goto restart;
  588.                 case 'C': 
  589.                      sprintf( Cmd, "chkdsk %s /f", Argv2 ); 
  590.                      system( Cmd ); 
  591.                      drain();
  592.                      hitakey();
  593.                      goto restart;
  594.                 case 'D': 
  595.                      sprintf( Cmd, "DIR %s /p", Argv2 ); 
  596.                      system( Cmd ); 
  597.                      drain();
  598.                      hitakey();
  599.                      goto restart;
  600.                 case 'E': 
  601.                      sprintf( Cmd, "erase %s*.*", Argv2 );
  602.                      printf( "%s\n", Cmd );
  603.                      system( Cmd ); 
  604.                      drain();
  605.                      hitakey();
  606.                      goto restart;
  607.                 case 'F': 
  608.                      sprintf( Cmd, "dothework %s /u", Argv2 ); 
  609.                      system( Cmd ); 
  610.                      drain();
  611.                      hitakey();
  612.                      goto restart;
  613.                 case 'Q': 
  614.                      quit();
  615.                 case 'S': 
  616.                      printf( "DOS doorway, type EXIT to return\n" );
  617.                      system( "COMMAND" );
  618.                      goto restart;
  619.                 case 'W': 
  620.                      walkdriver();
  621.                      goto restart;
  622.                 default:
  623.                      goto restart;
  624.         }
  625.     }
  626.     return( 0 );
  627. }
  628. /***************************************************************/
  629. /*                                                             */
  630. /*                                                             */
  631. /*                                                             */
  632. /*                                                             */
  633. /***************************************************************/
  634.  
  635.